package cn.kinoko.common.utils;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * Bean属性拷贝工具
 *
 * @author kinoko
 */
@Slf4j
public class BeanHelper {

    /**
     * 分页拷贝
     *
     * @param source   源数据
     * @param tClass   目标类型
     * @param function 拷贝后处理
     * @param <T>      目标类型
     * @return 目标分页
     */
    public static <T> Page<T> copyPage(Page<?> source, Class<T> tClass, Consumer<T> function) {
        List<T> newRecords = source.getRecords().stream().map(item -> {
            T t = copyProperties(item, tClass);
            function.accept(t);
            return t;
        }).toList();
        Page<T> target = Page.of(source.getCurrent(), source.getSize(), source.getTotal());
        target.setRecords(newRecords);
        return target;
    }

    /**
     * 分页拷贝
     *
     * @param source 源数据
     * @param tClass 目标类型
     * @param <T>    目标类型
     * @return 目标分页
     */
    public static <T> Page<T> copyPage(Page<?> source, Class<T> tClass) {
        List<T> newRecords = copyWithCollection(source.getRecords(), tClass);
        Page<T> target = Page.of(source.getCurrent(), source.getSize(), source.getTotal());
        target.setRecords(newRecords);
        return target;
    }

    public static <T> T copyProperties(Object source, Class<T> tClass) {
        try {
            Constructor<T> constructor = tClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            T target = constructor.newInstance();

            BeanUtils.copyProperties(source, target);
            return target;
        } catch (Exception e) {
            log.error("【数据转换】数据转换出错，目标对象{}构造函数异常", tClass.getName(), e);
            return null;
        }
    }

    public static <T> T copyProperties(Map<String, Object> source, Class<T> tClass) {
        try {
            Constructor<T> constructor = tClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            T target = constructor.newInstance();

            BeanUtil.fillBeanWithMap(source, target, false);
            return target;
        } catch (Exception e) {
            log.error("【数据转换】数据转换出错，目标对象{}构造函数异常", tClass.getName(), e);
            return null;
        }
    }


    public static <T> List<T> copyWithCollection(List<?> sourceList, Class<T> target) {
        try {
            return sourceList.parallelStream().map(s -> copyProperties(s, target)).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("【数据转换】数据转换出错，目标对象{}构造函数异常", target.getName(), e);
            return null;
        }

    }

    public static <T> Set<T> copyWithCollection(Set<?> sourceList, Class<T> target) {
        try {
            return sourceList.parallelStream().map(s -> copyProperties(s, target)).collect(Collectors.toSet());
        } catch (Exception e) {
            log.error("【数据转换】数据转换出错，目标对象{}构造函数异常", target.getName(), e);
            return null;
        }
    }
}
